#include "ListaCompras.hpp"

#include <cstring>
#include <cstdlib>
#include <algorithm>

#include "sqlite.hpp"



void
ListaCompras::carregaLista(const char *nomeArquivo)
{
	std::string msg;
	SQLiteDB db;

	// tenta abrir o banco de dados
	if (db.open(nomeArquivo, msg))
	{
		// cria a tabela de itens
		const char *sql0 =
			"create table if not exists item_lista_compra ("
			"id int primary key, "
			"descricao varchar(50) unique not null, "
			"preco_unitario real, "
			"quantidade int);";
		if (db.exec(sql0, msg))
		{
			// obtem os itens da tabela
			const char *sql1 = "select descricao, quantidade, preco_unitario from item_lista_compra;";

			auto cb =
				[this] (int argc, char *argv[], char **colNames)
				{
					ItemLista item;

					for (int i = 0; i < argc; ++i)
						if (strcmp(colNames[i], "id"))
							item.id = atoi(argv[i]);
						else if (strcmp(colNames[i], "descricao") == 0)
							item.descricao = argv[i];
						else if (strcmp(colNames[i], "preco_unitario") == 0)
							item.precoUnitario = atof(argv[i]);
						else if (strcmp(colNames[i], "quantidade") == 0)
							item.quantidade = atoi(argv[i]);

					itens_.push_back(item);
				};

			db.exec(sql1, msg, cb);
		}
	}

	if (!msg.empty())
		throw ListaComprasException(msg.c_str());
}

void
ListaCompras::gravaLista(const char *nomeArquivo)
{
	std::string msg;
	SQLiteDB db;
	if (db.open(nomeArquivo, msg) && db.exec("begin;", msg))
	{
		// apaga os itens anteriores
		if (db.exec("delete from item_lista_compra;", msg))
		{
			// insere os itens atuais
			const char *sql0 =
				"insert into item_lista_compra (descricao, quantidade, preco_unitario) "
				"values (?, ?, ?);";
			auto stmt = db.createStatement(sql0, msg);
			if (stmt)
				for (auto item : itens_)
				{
					if (!stmt->reset(msg))
						break;

					if (!stmt->bind(1, item.descricao.c_str(), msg))
						break;
					if (!stmt->bind(2, item.quantidade, msg))
						break;
					if (!stmt->bind(3, item.precoUnitario, msg))
						break;

					if (!stmt->step(msg))
						break;

					item.id = (int)db.lastInsertRowId();
				}

			std::string lastMsg;
			db.exec(msg.empty() ? "commit;" : "rollback;", lastMsg);
		}
	}

	if (!msg.empty())
		throw ListaComprasException(msg.c_str());
}

void
ListaCompras::incluiItem(ItemLista const &item)
{
	// item ja existe
	auto p = std::find_if(itens_.begin(), itens_.end(),
		[&item](ItemLista const &itemL) { return itemL.descricao == item.descricao; });
	if (p != itens_.end())
		throw ListaComprasException("Item ja esta cadastrado.");
	itens_.push_back(item);
}

void
ListaCompras::removeItem(int id)
{
	itens_.remove_if([id] (ItemLista const &item) { return item.id == id; });
}

void
ListaCompras::atualizaItem(ItemLista const &item)
{
	auto p = std::find_if(itens_.begin(), itens_.end(),
		[&item] (ItemLista const &itemL) { return itemL.id == item.id; });
	if (p != itens_.end())
	{
		p->descricao = item.descricao;
		p->precoUnitario = item.precoUnitario;
		p->quantidade = item.quantidade;
	}
	else
		throw ListaComprasException("Item nao encontrado na lista");
}

int
ListaCompras::size() const
{
	return (int)itens_.size();
}

std::list<ItemLista>::const_iterator
ListaCompras::begin() const
{
	return itens_.begin();
}

std::list<ItemLista>::const_iterator
ListaCompras::end() const
{
	return itens_.end();
}
